﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using QuickGraph;
using QuickGraph.Algorithms.ShortestPath;
using QuickGraph.Serialization;
using GraphMLComplexType;

namespace ComplexNetCentralityLib
{
    public class ComplexNetCentrality
    {
        public static TEdge CreateEdge<TVertex, TEdge>(TVertex source, TVertex target, string desc)
            where TVertex : IGraphMLComplexType, new()
            where TEdge : Edge<IGraphMLComplexType>
        {
            TEdge edge = (TEdge)new Edge<IGraphMLComplexType>(source, target);
            return edge;
        }

        public static double weights(EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType> edge)
        {
            return 1.0;
        }

        public static void degreeCentralityImportance(AdjacencyGraph<IGraphMLComplexType, EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>> socialNetwork)
        {
            foreach(var node in socialNetwork.Vertices)
            {
                List<Edge<IGraphMLComplexType>> edgeList = new List<Edge<IGraphMLComplexType>>();
                foreach (var e in socialNetwork.Edges)
                {
                    if(!edgeList.Contains(e)&&(e.Source == node || e.Target == node)) edgeList.Add(e);
                }
                double importance = (double)edgeList.Count / (double)(socialNetwork.VertexCount - 1);
                if(node.Keys.ContainsKey("importance"))
                {
                    node.Keys["importance"] = importance.ToString();
                }
                else
                {
                    node.Keys.Add("importance", importance.ToString());
                }
            }
        }

        public static void radiusCentralityImportance(AdjacencyGraph<IGraphMLComplexType, EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>> socialNetwork)
        {
            var fw = new FloydWarshallAllShortestPathAlgorithm<IGraphMLComplexType, EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>>(socialNetwork, weights);
            fw.Compute();
            foreach (var source in socialNetwork.Vertices)
            {
                int max = 0, count = 0;
                foreach (var target in socialNetwork.Vertices)
                {
                    if (!source.Equals(target))
                    {
                        IEnumerable<EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>> path;
                        if (fw.TryGetPath(source, target, out path))
                        {
                            count = 0;
                            foreach (var edge in path) count++;
                            if (count > max) max = count;
                        }
                        double importance = 0;
                        if(max != 0)
                            importance = 1 / max;
                        if (source.Keys.ContainsKey("importance"))
                        {
                            source.Keys["importance"] = importance.ToString();
                        }
                        else
                        {
                            source.Keys.Add("importance", importance.ToString());
                        }
                    }
                }
            }
        }

        public static void closenessCentralityImportance(AdjacencyGraph<IGraphMLComplexType, EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>> socialNetwork)
        {
            var fw = new FloydWarshallAllShortestPathAlgorithm<IGraphMLComplexType, EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>>(socialNetwork, weights);
            fw.Compute();
            foreach (var source in socialNetwork.Vertices)
            {
                int sum = 0;
                foreach (var target in socialNetwork.Vertices)
                {
                    if (!source.Equals(target))
                    {
                        IEnumerable<EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>> path;
                        if (fw.TryGetPath(source, target, out path))
                        {
                            foreach (var edge in path) sum++;
                        }
                        double importance = 0;
                        if(sum != 0)
                            importance = (socialNetwork.VertexCount - 1) / sum;
                        
                        if (source.Keys.ContainsKey("importance"))
                        {
                            source.Keys["importance"] = importance.ToString();
                        }
                        else
                        {
                            source.Keys.Add("importance", importance.ToString());
                        }
                        
                    }
                }
            }
        }

        public static void betweennessCentralityImportance(AdjacencyGraph<IGraphMLComplexType, EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>> socialNetwork)
        {
            var fw = new FloydWarshallAllShortestPathAlgorithm<IGraphMLComplexType, EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>>(socialNetwork, weights);
            fw.Compute();
            foreach (var i in socialNetwork.Vertices)
            {
                double sum = 0.0;
                foreach (var x in socialNetwork.Vertices)
                {
                    foreach (var y in socialNetwork.Vertices)
                    {
                        if (!x.Equals(y))
                        {
                            int d_xy = 0, d_xiy = 0;
                            IEnumerable<EdgeWithAttributes.EdgeWithAttributes<IGraphMLComplexType>> path, path_x, path_y;
                            if (fw.TryGetPath(x, y, out path) && fw.TryGetPath(x, i, out path_x) && fw.TryGetPath(i, y, out path_y) )
                            {
                                foreach (var edge in path) d_xy++;
                                foreach (var edge in path_x) d_xiy++;
                                foreach (var edge in path_y) d_xiy++;
                                if (d_xy != 0) sum += (double)d_xiy / (double)d_xy;
                            }                                
                        }
                    }
                }

                double importance = 13.13;
                var div = (socialNetwork.VertexCount - 1) * (socialNetwork.VertexCount - 2);
                if (div != 0) importance = sum / div;

                if (i.Keys.ContainsKey("importance"))
                {
                    i.Keys["importance"] = importance.ToString();
                }
                else
                {
                    i.Keys.Add("importance", importance.ToString());
                }
            }
        }

    }
}
